package com.pine.dbant.common.plugin;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.pine.dbant.common.model.ConnectionInfo;
import com.pine.sunflower.core.LifeCycledAdapter;
import com.pine.sunflower.core.plugin.Configuration;
import lombok.extern.slf4j.Slf4j;

import javax.sql.DataSource;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author xiaoyuan
 * @create 2022/11/17
 **/
@Slf4j
public class DynamicDataSourceDruid extends LifeCycledAdapter implements DynamicDataSource {

    private Configuration configuration;

    public static Map<String, DruidDataSource> customDataSources = new ConcurrentHashMap<>();

    private static final String POOL_INITIAL_SIZE = "dbant.sql.pool.initialSize";

    private static final String POOL_MIN_IDLE = "dbant.sql.pool.minIdle";

    private static final String POOL_MAX_ACTIVE = "dbant.sql.pool.maxActive";

    private static final String POOL_REMOVE_ABANDONED = "dbant.sql.pool.removeAbandoned";

    private static final String POOL_REMOVE_ABANDONED_TIME_OUT = "dbant.sql.pool.removeAbandonedTimeout";

    private static final String POOL_MAX_WAIT = "dbant.sql.pool.maxWait";

    private static final String POOL_TIME_BETWEEN_CONNECT_ERROR_MILLIS = "dbant.sql.pool.timeBetweenConnectErrorMillis";

    public DynamicDataSourceDruid(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public void closeDataSource(String connId) {
        log.info("drop dataSources ,connId=" + connId);
        DruidDataSource dataSource = customDataSources.get(connId);
        if (dataSource != null) {
            dataSource.close();
            dataSource = null;
        }
        customDataSources.remove(connId);
    }

    @Override
    public DataSource getDataSource(ConnectionInfo connectionInfo) {
        String jdbcUrl = "";
        try {
            String id = connectionInfo.getId() +"@@"+connectionInfo.getDbName();
            DruidDataSource dataSource = customDataSources.get(id);
            if (dataSource == null) {
                log.info("create datasourcepoolName=" + id);
                jdbcUrl = concatJdbcUrl(connectionInfo);
                Properties properties = new Properties();
                properties.setProperty("url", jdbcUrl);
                properties.setProperty("driver", getDriver(connectionInfo));
                properties.setProperty("username", connectionInfo.getUsername());
                properties.setProperty("password", connectionInfo.getPwd());
                properties.setProperty("initialSize", this.configuration.getString(POOL_INITIAL_SIZE, "1"));
                properties.setProperty("minIdle", this.configuration.getString(POOL_MIN_IDLE, "1"));
                properties.setProperty("maxActive", this.configuration.getString(POOL_MAX_ACTIVE, "10"));
                properties.setProperty("removeAbandoned", this.configuration.getString(POOL_REMOVE_ABANDONED, "true"));
                properties.setProperty("removeAbandonedTimeout", this.configuration.getString(POOL_REMOVE_ABANDONED_TIME_OUT, "180"));
                properties.setProperty("maxWait", this.configuration.getString(POOL_MAX_WAIT, "15000"));
                properties.setProperty("logAbandoned", "true");
                DruidDataSource druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
                druidDataSource.setTimeBetweenConnectErrorMillis(this.configuration.getLong(POOL_TIME_BETWEEN_CONNECT_ERROR_MILLIS, 300000L));
                druidDataSource.setTestWhileIdle(true);
                druidDataSource.setDefaultAutoCommit(false);
                customDataSources.put(id, druidDataSource);
                return druidDataSource;
            }
            return dataSource;
        } catch (Exception e) {
            log.error("连接池创建失败。jdbcUrl={}", jdbcUrl, e);
            return null;
        }
    }

    public String concatJdbcUrl(ConnectionInfo connectionInfo) {
        throw new UnsupportedOperationException("不支持该操作");
    }

    public String getDriver(ConnectionInfo connectionInfo) {
        throw new UnsupportedOperationException("不支持该操作");
    }

    @Override
    public void doStop() {
        customDataSources.values().forEach(DruidDataSource::close);
        customDataSources.clear();
    }
}
